package al.xc.common.util;

import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import sun.nio.ch.IOUtil;

import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.apache.http.HttpVersion.HTTP;

public class HttpUtils {

    private static HttpClient httpClient;
    private static SSLConnectionSocketFactory sslConnectionSocketFactory;
    private static SSLContextBuilder sslContextBuilder;

    static {
        try {
            sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (x509Certificates, s) -> true);
            sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(),
                    new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE);
        } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            throw new ExceptionInInitializerError();
        }

        Registry<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", new PlainConnectionSocketFactory())
                .register("https", sslConnectionSocketFactory)
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registryBuilder);
        cm.setMaxTotal(512);
        cm.setDefaultMaxPerRoute(64);
        httpClient = HttpClients.custom().setConnectionManager(cm).build();
    }

    /**
     * http Post请求
     * @param url
     * @param data
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static CloseableHttpResponse httpPost(String url, Map<String,Object> data) throws ParseException, IOException {

        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);

        List<NameValuePair> nvps = new ArrayList<>();
        if (null != data && 0 != data.size()) {
            for(Map.Entry<String, Object> entry : data.entrySet()) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
            }
        }
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));

        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");

        return client.execute(httpPost);
    }

    /**
     * http Post 请求
     * @param requestUrl
     * @param outValue
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static String httpPost(String requestUrl, String outValue, String contentType) throws ParseException, IOException {
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            conn.setRequestMethod("POST");
            conn.setRequestProperty("content-type", contentType);
            // 当outputStr不为null时向输出流写数据
            if (null != outValue) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outValue.getBytes(Charsets.UTF_8));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("连接超时：{}"+ ce);
        } catch (Exception e) {
            System.out.println("https请求异常：{}"+ e);
        }
        return null;
    }

    /**
     * http json Post 请求
     * @param requestUrl
     * @param outValue
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static String httpPostJson(String requestUrl, String outValue)  throws ParseException, IOException {
        return httpPost(requestUrl, outValue, "application/json");
    }

    /**
     * http xml Post 请求
     * @param requestUrl
     * @param outValue
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static String httpPostXml(String requestUrl, String outValue)  throws ParseException, IOException {
        return httpPost(requestUrl, outValue, "application/x-www-form-urlencoded");
    }

    /**
     * http Get请求
     * @param url
     * @return
     */
    public static CloseableHttpResponse httpget(String url) throws IOException {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
        CloseableHttpClient client = HttpClients.createDefault();
        return client.execute(httpGet);
    }

    /**
     * HTTP POST 请求
     * @param url
     * @param body
     * @param headers
     * @return
     * @throws IOException
     */
    public static String httpPostForm(String url, Map<String,String> body, Map<String, String> headers) throws IOException {
        HttpPost http = new HttpPost(url);
        try {
            setPostEntity(http, body);
            setPostHeader(http, headers);
            setConfig(http, 6000, 10000);
            HttpResponse response = httpClient.execute(http);
            return IOUtils.toString(response.getEntity().getContent(), "UTF-8");
        } finally {
            http.releaseConnection();
        }
    }

    /**
     * HTTP POST 请求
     * @param url
     * @param body
     * @param headers
     * @return
     * @throws IOException
     */
    public static String httpPostForm(String url, String body, Map<String, String> headers) throws IOException {
        HttpPost http = new HttpPost(url);
        try {
            setStringEntity(http, body);
            setPostHeader(http, headers);
            setConfig(http, 6000, 10000);
            HttpResponse response = httpClient.execute(http);
            return IOUtils.toString(response.getEntity().getContent(), "UTF-8");
        } finally {
            http.releaseConnection();
        }
    }

    private static void setPostEntity(HttpPost http, Map<String,String> body) {
        if (null == body || body.isEmpty()) {
            return;
        }
        List<NameValuePair> formList = new ArrayList<>();
        for (Map.Entry<String, String> entry : body.entrySet()) {
            formList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formList, Charsets.UTF_8);
        http.setEntity(entity);
    }

    private static void setStringEntity(HttpPost http, String body) {
        StringEntity entity = new StringEntity(body, ContentType.APPLICATION_JSON);
        http.setEntity(entity);
    }

    private static void setPostHeader(HttpPost http, Map<String,String> headers) {
        if (null == headers || headers.isEmpty()) {
            return;
        }
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            http.setHeader(entry.getKey(), entry.getValue());
        }
    }

    private static void setConfig(HttpRequestBase base, int connectTimeout, int socketTimeout) {
        RequestConfig.Builder builder = RequestConfig.custom();

        if (connectTimeout >= 0) {
            builder.setConnectTimeout(connectTimeout);
        }

        if (socketTimeout >= 0) {
            builder.setSocketTimeout(socketTimeout);
        }

        base.setConfig(builder.build());
    }
}
